pcall(require, "impatient")

-- Utility functions {{{

local function const(value)
  return function()
    return value
  end
end
local function wrap(func)
  return function()
    func()
  end
end

local map = vim.keymap.set
local function remap(mode, lhs, rhs, opts)
  vim.keymap.set(mode, lhs, rhs, vim.tbl_extend("force", { remap = true }, opts or {}))
end
local function cmdmap(mode, lhs, rhs, opts)
  map(mode, lhs, function()
    vim.cmd(rhs)
  end, opts)
end
local function buf_map(buf, mode, lhs, rhs, opts)
  vim.keymap.set(mode, lhs, rhs, vim.tbl_extend("force", { buffer = buf }, opts or {}))
end

-- }}}

-- Options {{{

vim.g.tex_flavor = "latex"
vim.opt.autowriteall = true
vim.opt.breakindent = true
vim.opt.completeopt = { "menuone" }
vim.opt.conceallevel = 2
vim.opt.expandtab = true
vim.opt.fillchars = { fold = " ", stl = " ", stlnc = " " }
vim.opt.foldmethod = "marker"
vim.opt.foldopen = { "mark", "percent", "quickfix", "search", "tag", "undo" }
vim.opt.foldtext = "v:lua.Foldtext(v:foldstart, v:foldend)"
function Foldtext(foldstart, foldend)
  local line = vim.api.nvim_buf_get_lines(0, foldstart - 1, foldstart, true)[1]
  local num_lines = foldend - foldstart + 1
  local rest = line:gsub("^%s*", ""):gsub("%s*{{{", "") -- }}}
  local commentstring = vim.opt.commentstring:get():gsub("%s*%%s", "")
  if commentstring and rest:sub(1, #commentstring) == commentstring then
    rest = rest:sub(#commentstring + 1):gsub("^%s*", "")
  end
  return ("%s⟦%s⟧ %s"):format(line:match "%s*", num_lines, rest)
end

vim.opt.gdefault = true
vim.opt.hlsearch = false
vim.opt.lazyredraw = true
vim.opt.linebreak = true
vim.opt.list = true
vim.opt.listchars = { tab = "⎸ ", trail = "⎵", nbsp = "⸱" }
vim.opt.modeline = true
vim.opt.mouse = ""
vim.opt.number = true
vim.opt.scrolloff = 999
vim.opt.shiftround = true
vim.opt.shiftwidth = 0
vim.opt.shortmess = "aoOstTWAcF"
vim.opt.showmode = false
vim.opt.signcolumn = "yes"
vim.opt.tabstop = 2
vim.opt.termguicolors = true
vim.opt.timeout = false
vim.opt.undofile = true
vim.opt.virtualedit = "block"
vim.fn.setcellwidths {
  { 0x27C0, 0x27EF, 1 }, -- Miscellaneous Mathematical Symbols-A
  -- { 0xE700, 0xE7C5, 2 }, -- Devicons
  { 0xE200, 0xE2A9, 2 }, -- Font Awesome Extension
  { 0xF0001, 0xF1AF0, 2 }, -- Material Design Icons
}

-- }}}

-- Mappings {{{

cmdmap("n", ";", "w")
cmdmap("n", "g;", "noautocmd w", { desc = "Write file without running autocommands" })
cmdmap("n", "<c-j>", "") -- unlearn
cmdmap("n", "<c-k>", "") -- unlearn
cmdmap("n", "Q", "q")
cmdmap("n", "ZC", "q", { desc = "Close window" })
cmdmap("n", "ZZ", "exit!", { desc = "Write if modified and close window" })
cmdmap("n", "m,", "SidewaysLeft")
cmdmap("n", "m.", "SidewaysRight")
map("", "<a-h>", "") -- unlearn
map("", "<a-j>", "") -- unlearn
map("", "<a-k>", "") -- unlearn
map("", "<a-l>", "") -- unlearn
map("", "<c-v>", "v")
map("", "<space>", ":")
map("", "H", "^")
map("", "L", "$")
map("", "N", function()
  return vim.v.searchforward == 1 and "N" or "n"
end, { expr = true })
map("", "n", function()
  return vim.v.searchforward == 1 and "n" or "N"
end, { expr = true })
map("", "v", "<c-v>")
map("n", ",", "")
map("n", "-u", "yypVr-", { desc = "Add underline made of dashes" })
map("n", "<cr>", "o<esc>")
map("n", "=u", "yypVr=", { desc = "Add underline made of equal signs" })
map("n", "^", require("templates").insert_template)
map("n", "g<cr>", "O<esc>", { desc = "Prepend empty line" })
map("n", "gM", "m", { desc = "Set mark" })
map("n", "~", "g~l")
map("t", "<a-h>", "<c-\\><c-n><c-w>h")
map("t", "<a-j>", "<c-\\><c-n><c-w>j")
map("t", "<a-k>", "<c-\\><c-n><c-w>k")
map("t", "<a-l>", "<c-\\><c-n><c-w>l")
map("t", "<esc>", "<c-\\><c-n>")
remap("n", "M", "m$")
remap("n", "cW", "ciW", { desc = "Change WORD" })
remap("n", "cp", "cip", { desc = "Change paragraph" })
remap("n", "cw", "ciw", { desc = "Change word" })
remap("n", "dW", "daW", { desc = "Delete WORD" })
remap("n", "dp", "dap", { desc = "Delete paragraph" })
remap("n", "dw", "daw", { desc = "Delete word" })
remap("n", "mW", "maW", { desc = "Move WORD" })
remap("n", "mp", "map", { desc = "Move paragraph" })
remap("n", "mw", "maw", { desc = "Move word" })
remap("n", "sW", "siW", { desc = "Surround WORD" })
remap("n", "sp", "sip", { desc = "Surround paragraph" })
remap("n", "ss", "cl", { desc = "Delete character and start insert mode" })
remap("n", "sw", "siw", { desc = "Surround word" })

-- additional unimpaired-like mappings
map("n", "yok", function()
  vim.opt.conceallevel = 2 - vim.opt.conceallevel:get()
end)

-- }}}

-- Miscellaneous {{{

vim.api.nvim_create_autocmd("BufReadPost", {
  callback = function()
    if not vim.b.jumped_to_last_position and vim.fn.line [['"]] >= 1 and vim.fn.line [['"]] <= vim.fn.line "$" then
      vim.cmd [[normal! g`"]]
      vim.b.jumped_to_last_position = true
    end
  end,
})

-- }}}

-- Plugins {{{

-- Bootstrap plugin manager {{{
local lazypath = vim.fn.stdpath "data" .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system {
    "git",
    "clone",
    "--filter=blob:none",
    "--single-branch",
    "https://github.com/folke/lazy.nvim.git",
    lazypath,
  }
end
vim.opt.runtimepath:prepend(lazypath)
-- }}}

-- LSP on-attach callback {{{
local on_attach = function(before)
  return function(client, buf)
    if before then
      before(client, buf)
    end
    buf_map(buf, "n", "+", wrap(vim.lsp.buf.code_action))
    buf_map(buf, "n", "K", wrap(vim.lsp.buf.hover))
    buf_map(buf, "n", "[d", wrap(vim.diagnostic.goto_prev), { desc = "Previous diagnostic" })
    buf_map(buf, "n", "]d", wrap(vim.diagnostic.goto_next), { desc = "Next diagnostic" })
    buf_map(buf, "n", "cm", wrap(vim.lsp.buf.rename))
    buf_map(buf, "n", "gl", wrap(vim.diagnostic.open_float), { desc = "Open diagnostics" })
    buf_map(buf, "n", "gq", function()
      vim.lsp.buf.format { async = true }
    end, { desc = "Format buffer" })
    MiniClue.ensure_buf_triggers()
    if client.server_capabilities.definitionProvider then
      buf_map(buf, "n", "gD", wrap(vim.lsp.buf.declaration), { desc = "Jump to declaration" })
      buf_map(buf, "n", "gd", wrap(vim.lsp.buf.definition), { desc = "Jump to definition" })
    end
    if client.server_capabilities.documentFormattingProvider then
      vim.api.nvim_create_autocmd("BufWritePre", {
        buffer = buf,
        callback = wrap(vim.lsp.buf.format),
      })
    end
  end
end
-- }}}

require("lazy").setup({
  { name = "arturo", "https://github.com/xigoi/vim-arturo", ft = "arturo" },
  { name = "actually", "https://github.com/mong8se/actually.nvim" },
  { name = "automkdir", "https://github.com/mateuszwieloch/automkdir.nvim", event = "VeryLazy" },
  -- ccc {{{
  {
    name = "ccc",
    "https://github.com/uga-rosa/ccc.nvim",
    config = function()
      local ccc = require "ccc"
      ccc.setup {
        inputs = { ccc.input.rgb, ccc.input.oklch, ccc.input.hsl },
        pickers = {
          ccc.picker.hex,
          ccc.picker.css_rgb,
          ccc.picker.css_hsl,
          ccc.picker.css_hwb,
          ccc.picker.css_lab,
          ccc.picker.css_lch,
          ccc.picker.css_oklab,
          ccc.picker.css_oklch,
          ccc.picker.css_name,
        },
        exclude_pattern = {
          hex = { "[%w_]{{pattern}}", "{{pattern}}[g-zG-Z_]" },
          css_name = { "[%w_\\]{{pattern}}", "{{pattern}}[%w_]" },
        },
        highlighter = { auto_enable = true },
        recognize = { output = true },
      }
      cmdmap("n", "co", "CccPick")
      map("i", "<a-c>", "<plug>(ccc-insert)")
    end,
  },
  -- }}}
  { name = "closetag", "https://github.com/alvan/vim-closetag", ft = "html" },
  -- cutlass {{{
  {
    name = "cutlass",
    "https://github.com/gbprod/cutlass.nvim",
    opts = { cut_key = "m", override_del = true },
  },
  -- }}}
  -- debugprint {{{
  {
    name = "debugprint",
    "https://github.com/andrewferrier/debugprint.nvim",
    keys = {
      { mode = "n", "g?p" },
      { mode = "n", "g?P" },
      { mode = "n", "g?v" },
      { mode = "n", "g?V" },
      { mode = "n", "g?o" },
      { mode = "n", "g?O" },
      { mode = "x", "g?v" },
      { mode = "x", "g?V" },
    },
    opts = {
      filetypes = {
        c = { left = 'printf("', right = '\\n"), fflush(stdout);' },
        nim = { left = 'debugEcho("', right = '")', mid_var = '", $', right_var = ")" },
      },
    },
  },
  -- }}}
  { name = "editorconfig", "https://github.com/editorconfig/editorconfig-vim" },
  -- git-conflict {{{
  {
    name = "git-conflict",
    "https://github.com/akinsho/git-conflict.nvim",
    opts = { default_mappings = false },
  },
  -- }}}
  { name = "impatient", "https://github.com/lewis6991/impatient.nvim" },
  -- {
  --   name = "lean",
  --   "https://github.com/Julian/lean.nvim",
  --   opts = { lsp = { on_attach = on_attach() } },
  -- },
  -- lspconfig {{{
  {
    name = "lspconfig",
    "https://github.com/neovim/nvim-lspconfig",
    config = function()
      local lspconfig = require "lspconfig"
      local lsp_setup = function(server, config, before)
        config.on_attach = on_attach(before)
        server.setup(config)
      end
      local no_format = function(client)
        client.server_capabilities.documentFormattingProvider = false
      end
      lsp_setup(lspconfig.clangd, {})
      lsp_setup(lspconfig.gdscript, {})
      require("neodev").setup {}
      lsp_setup(lspconfig.lua_ls, {}, no_format)
      -- nimble install nimlangserver
      -- lsp_setup(lspconfig.nim_langserver, {})
      -- pipx install 'python-lsp-server[all]'
      lsp_setup(lspconfig.pylsp, {}, no_format)
      -- npm install -g typescript typescript-language-server
      lsp_setup(lspconfig.tsserver, {}, no_format)
      local null_ls = require "null-ls"
      lsp_setup(null_ls, {
        sources = {
          null_ls.builtins.code_actions.gitsigns,
          -- null_ls.builtins.diagnostics.cppcheck.with {
          --   extra_args = { "--language=c++", "--enable=style", "--inline-suppr", "--suppress=constParameter" },
          -- },
          null_ls.builtins.formatting.black,
          null_ls.builtins.formatting.clang_format,
          -- npm install -g @fsouza/prettierd
          null_ls.builtins.formatting.prettierd,
          -- null_ls.builtins.formatting.reorder_python_imports,
          null_ls.builtins.formatting.stylua,
          require "null-sources/nimcheck",
          require "null-sources/nph",
          require "null-sources/vfmt",
          require "null-sources/xidoc",
        },
      })
    end,
  },
  -- }}}
  { name = "luapad", "https://github.com/rafcamlet/nvim-luapad", cmd = { "Luapad", "LuaRun" } },
  -- manual-pairs {{{
  {
    name = "manual-pairs",
    "https://git.sr.ht/~xigoi/nvim-manual-pairs",
    event = "VeryLazy",
    config = function()
      local manual_pairs = require "manual-pairs"
      manual_pairs.map_pair("<a-9>", "(", ")")
      manual_pairs.map_pair("<a-s-9>", "(", ")")
      manual_pairs.map_pair("<a-[>", "[", "]")
      manual_pairs.map_pair("<a-s-[>", "{", "}")
      manual_pairs.map_pair("<a-'>", "'", "'")
      manual_pairs.map_pair("<a-s-'>", '"', '"')
      manual_pairs.map_pair("<a-,>", "<", ">")
      manual_pairs.map_pair("<a-s-,>", "<", ">")
      manual_pairs.map_pair("<a-`>", "`", "`")
      manual_pairs.map_pair("<a-\\>", "|", "|")
      manual_pairs.map_pair("<a-s-\\>", "|", "|")
      manual_pairs.map_pair("<a-/>", "/", "/")
      manual_pairs.map_pair("<a-space>", " ", " ")
      manual_pairs.map_fly("<a-0>", ")")
      manual_pairs.map_fly("<a-s-0>", ")")
      manual_pairs.map_fly("<a-]>", "]")
      manual_pairs.map_fly("<a-s-]>", "}")
      manual_pairs.map_fly("<a-s-.>", ">")
      manual_pairs.map_cr "<a-cr>"
      manual_pairs.map_right "<a-l>"
      manual_pairs.map_backspace "<a-bs>"
      -- to break the habit
      map("i", "<a-p>", "")
    end,
  },
  -- }}}
  -- mini {{{
  {
    name = "mini",
    "https://github.com/echasnovski/mini.nvim",
    config = function()
      require("mini.ai").setup { custom_textobjects = { x = { "%b[]", "^%[[^%s%[%]]*%s*().*()%]$" } } }
      -- mini.bufremove {{{
      local minibufremove = require "mini.bufremove"
      minibufremove.setup {}
      map("n", "--", minibufremove.delete, { desc = "Delete the current buffer" })
      -- }}}
      require("mini.bracketed").setup { indent = { suffix = "" } }
      -- mini.clue {{{
      local miniclue = require "mini.clue"
      miniclue.setup {
        triggers = {
          { mode = "c", keys = "<C-r>" },
          { mode = "i", keys = "<C-r>" },
          { mode = "i", keys = "<c-x>" },
          { mode = "n", keys = "," },
          { mode = "n", keys = "-" },
          { mode = "n", keys = "=" },
          { mode = "n", keys = "<c-w>" },
          { mode = "n", keys = "<leader>" },
          { mode = "n", keys = "[" },
          { mode = "n", keys = "]" },
          { mode = "n", keys = "`" },
          -- { mode = "n", keys = "c" },
          -- { mode = "n", keys = "d" },
          { mode = "n", keys = "g" },
          { mode = "n", keys = "m" },
          { mode = "n", keys = "s" },
          { mode = "n", keys = "z" },
          { mode = "n", keys = "Z" },
          { mode = "n", keys = '"' },
          { mode = "x", keys = "<leader>" },
          { mode = "x", keys = "`" },
          { mode = "x", keys = "g" },
          { mode = "x", keys = "z" },
          { mode = "x", keys = '"' },
        },
        clues = {
          miniclue.gen_clues.builtin_completion(),
          miniclue.gen_clues.g(),
          miniclue.gen_clues.marks(),
          miniclue.gen_clues.registers(),
          miniclue.gen_clues.windows(),
          miniclue.gen_clues.z(),
          { mode = "n", keys = "ZQ", desc = "Force close window" },
          { mode = "n", keys = "]b", postkeys = "]" },
          { mode = "n", keys = "[b", postkeys = "[" },
          { mode = "n", keys = "ge", postkeys = "g" },
          { mode = "n", keys = "gE", postkeys = "g" },
        },
        window = { delay = 0 },
      }
      -- }}}
      require("mini.comment").setup {}
      -- mini.completion {{{
      require("mini.completion").setup {
        delay = { completion = math.huge, info = 0, signature = 0 },
        set_vim_settings = false,
        mappings = { force_fallback = "" },
      }
      -- }}}
      -- mini.diff {{{
      require("mini.diff").setup {
        view = { signs = { add = "+", change = "Δ", delete = "₋" } },
        delay = { text_change = 0 },
        mappings = { reset = "U" },
      }
      -- }}}
      require("mini.files").setup {}
      require("mini.indentscope").setup { draw = { delay = 0, animation = const(0) } }
      -- mini.jump {{{
      require("mini.jump").setup {
        allowed_windows = { not_current = false },
        mappings = { repeat_jump = "" },
      }
      -- }}}
      -- mini.jump2d {{{
      require("mini.jump2d").setup {
        labels = [[abcdefghijklmnopqrstuvwxyz0123456789]],
        view = { dim = true },
        mappings = { start_jumping = "'" },
        delay = { highlight = math.huge, idle_stop = math.huge },
      }
      -- }}}
      -- mini.operators {{{
      require("mini.operators").setup {}
      map("n", "gR", "grL", { remap = true, desc = "Replace to end of line" })
      -- }}}
      -- mini.pick {{{
      require("mini.pick").setup {}
      map("n", ",b", wrap(MiniPick.builtin.buffers), { desc = "Pick buffer" })
      map("n", ",f", wrap(MiniPick.builtin.files), { desc = "Pick file" })
      map("n", ",h", wrap(MiniPick.builtin.help), { desc = "Pick help" })
      -- }}}
      require("mini.splitjoin").setup {}
      require("mini.statusline").setup {}
      -- mini.surround {{{
      require("mini.surround").setup {
        n_lines = 1000,
        mappings = {
          add = "s",
          delete = "ds",
          find_left = "[s",
          find = "]s",
          highlight = "",
          replace = "cs",
          update_n_lines = "",
          suffix_last = "",
          suffix_next = "",
        },
        custom_surroundings = {
          l = {
            input = { [[\%w+%b{}]], "^.-{().*()}$" },
            output = function()
              local command = MiniSurround.user_input "LaTeX command name"
              return command and { left = ([[\%s{]]):format(command), right = "}" }
            end,
          },
          L = {
            input = { [[\begin{(%w*)}.-\end{%1}]], [[^\begin{.-}().-()\end{.-}$]] },
            output = function()
              local environment = MiniSurround.user_input "LaTeX environment name"
              return environment
                and {
                  left = ([[\begin{%s}]]):format(environment),
                  right = ([[\end{%s}]]):format(environment),
                }
            end,
          },
          x = {
            input = { "%b[]", "^%[[^%s%[%]]*%s*().*()%]$" },
            output = function()
              local command = MiniSurround.user_input "xidoc command name"
              return command and { left = ("[%s "):format(command), right = "]" }
            end,
          },
        },
      }
      remap("n", "S", "sL")
      remap("", "[(", "[s(", { desc = "Previous surrounding (" })
      remap("", "])", "]s)", { desc = "Next surrounding )" })
      remap("", "[[", "[s[", { desc = "Previous surrounding [" })
      remap("", "]]", "]s]", { desc = "Next surrounding ]" })
      remap("", "[{", "[s{", { desc = "Previous surrounding {" })
      remap("", "]}", "]s}", { desc = "Next surrounding }" })
      -- }}}
      require("mini.tabline").setup {}
    end,
  },
  -- }}}
  { name = "neodev", "https://github.com/folke/neodev.nvim" },
  -- neogit {{{
  {
    name = "neogit",
    "https://github.com/TimUntersberger/neogit",
    keys = { { mode = "n", "gy", desc = "Open Neogit menu" } },
    config = function()
      local neogit = require "neogit"
      neogit.setup { disable_commit_confirmation = true, kind = "replace" }
      map("n", "gy", neogit.open)
    end,
  },
  -- }}}
  -- netman {{{
  {
    name = "netman",
    "https://github.com/miversen33/netman.nvim",
    config = function()
      require "netman"
    end,
  },
  -- }}}
  -- none-ls {{{
  {
    name = "none-ls",
    "https://github.com/nvimtools/none-ls.nvim",
    dependencies = { "https://github.com/nvim-lua/plenary.nvim" },
  },
  -- }}}
  -- nrpattern {{{
  {
    name = "nrpattern",
    "https://github.com/zegervdv/nrpattern.nvim",
    keys = {
      { mode = "n", "<c-a>" },
      { mode = "n", "<c-x>" },
      { mode = "v", "<c-a>" },
      { mode = "v", "<c-x>" },
      { mode = "v", "g<c-a>" },
      { mode = "v", "g<c-x>" },
    },
    config = function()
      require("nrpattern").setup(vim.tbl_extend("error", require "nrpattern.default", {
        [{ "no", "yes" }] = { priority = 10 },
        [{ "off", "on" }] = { priority = 10 },
        [{ "and", "or" }] = { priority = 10 },
        [{ "all", "ex" }] = { priority = 10, filetypes = { "xidoc" } },
        [{ "solution", "spoiler-solution" }] = { priority = 10, filetypes = { "xidoc" } },
      }))
    end,
  },
  -- }}}
  { name = "otherwise", "https://git.sr.ht/~xigoi/nvim-otherwise", ft = { "lua", "nim", "python", "v" } },
  { name = "parinfer", "https://github.com/gpanders/nvim-parinfer", ft = { "query" } },
  { name = "qbe", "https://github.com/perillo/qbe.vim", ft = { "qbe" } },
  -- rainbow-delimiters {{{
  {
    name = "rainbow-delimiters",
    "https://github.com/hiphish/rainbow-delimiters.nvim",
    config = function()
      vim.g.rainbow_delimiters = {
        highlight = { "Delimiter1", "Delimiter2", "Delimiter3", "Delimiter4", "Delimiter5", "Delimiter6" },
        query = { [""] = "rainbow-delimiters", javascript = "rainbow-parens" },
      }
    end,
  },
  -- }}}
  -- recorder {{{
  {
    name = "recorder",
    "https://github.com/chrisgrieser/nvim-recorder",
    keys = {
      { mode = "n", "q" },
      { mode = "n", "@" },
      { mode = "n", "cq" },
      { mode = "n", "<c-q>" },
      { mode = "n", "!" },
    },
    opts = { slots = { "x", "z" }, mapping = { playMacro = "@" } },
  },
  -- }}}
  { name = "repeat", "https://github.com/tpope/vim-repeat", event = "VeryLazy" },
  { name = "suda", "https://github.com/lambdalisue/suda.vim", cmd = { "SudaRead", "SudaWrite" } },
  -- summon {{{
  {
    name = "summon",
    "https://git.sr.ht/~xigoi/nvim-summon",
    keys = { { mode = "n", "$" } },
    config = function()
      map("n", "$", require("summon").summon_cursor)
    end,
  },
  -- }}}
  {
    name = "sideways",
    "https://github.com/andrewradev/sideways.vim",
    cmd = { "SidewaysLeft", "SidewaysRight" },
  },
  -- toggleterm {{{
  {
    name = "toggleterm",
    "https://github.com/akinsho/toggleterm.nvim",
    keys = { { mode = "n", "<c-t>" }, { mode = "i", "<c-t>" } },
    opts = {
      open_mapping = "<c-t>",
      shade_terminals = false,
      on_create = function()
        buf_map(0, "n", "--", "i<c-e><c-u><c-d>")
        buf_map(0, "n", "<c-c>", "i<c-c><c-\\><c-n>")
        buf_map(0, "n", "<c-j>", "")
        buf_map(0, "n", "<c-k>", "")
        buf_map(0, "n", "<cr>", "i<up><cr><c-\\><c-n>")
        buf_map(0, "n", "<up>", "i<up>")
        buf_map(0, "n", "[b", "")
        buf_map(0, "n", "]b", "")
      end,
    },
  },
  -- }}}
  -- treesitter {{{
  {
    name = "treesitter",
    "https://github.com/nvim-treesitter/nvim-treesitter",
    config = function()
      require("nvim-treesitter.configs").setup {
        ensure_installed = {
          "bash",
          "c",
          "cpp",
          "css",
          "git_config",
          "gitattributes",
          "gitcommit",
          "gitignore",
          "html",
          "javascript",
          "json",
          "julia",
          "lua",
          "luap",
          "nim",
          "nim_format_string",
          "python",
          "query",
          "regex",
        },
        highlight = { enable = true },
        incremental_selection = {
          enable = true,
          keymaps = {
            init_selection = "<m-n>",
            node_incremental = "<m-n>",
            scope_incremental = "<m-b>",
            node_decremental = "<m-m>",
          },
        },
        indent = { enable = true },
        locals = { enable = true },
        endwise = { enable = true },
        otherwise = { enable = true },
      }
      local conceal_table = require "heine/conceal"
      vim.treesitter.query.add_directive("heine-conceal!", function(match, pattern, buffer, predicate, metadata)
        local capture_id = predicate[2]
        local node = match[capture_id]
        local symbol = vim.treesitter.get_node_text(node, buffer, metadata[capture_id])
        metadata.conceal = conceal_table[symbol]
      end)
      local parser_configs = require("nvim-treesitter.parsers").get_parser_configs()
      for _, lang in ipairs { "heine", "pikchr", "xidoc" } do
        parser_configs[lang] = {
          install_info = { url = "~/tree-sitter-" .. lang, files = { "src/parser.c" } },
        }
      end
      parser_configs.sixcat = {
        install_info = { url = "~/tree-sitter-sixcat", files = { "src/parser.c", "src/scanner.c" } },
      }
    end,
  },
  -- }}}
  { name = "treesitter-endwise", "https://github.com/RRethy/nvim-treesitter-endwise" },
  -- unicode {{{
  {
    name = "unicode",
    "https://github.com/chrisbra/unicode.vim",
    keys = {
      { mode = "i", "<c-x><c-z>" },
      { mode = "i", "<c-x><c-g>" },
      { mode = "n", "g1", desc = "Describe Unicode character at cursor" },
    },
    cmd = { "Digraphs", "UnicodeSearch", "UnicodeName", "DownloadUnicode", "UnicodeCache" },
    config = function()
      cmdmap("n", "g1", "UnicodeName")
    end,
  },
  -- }}}
  -- unicode-search {{{
  {
    name = "unicode-search",
    dir = "~/nvim-plugins/unicode-search",
    keys = {
      {
        mode = "i",
        "<a-u>",
        function()
          vim.opt.ignorecase = true
          require("unicode-search").mini_pick()
          vim.opt.ignorecase = false
        end,
        desc = "Find Unicode character",
      },
    },
  },
  -- }}}
  -- vimtex {{{
  {
    name = "vimtex",
    "https://github.com/lervag/vimtex",
    ft = "tex",
    config = function()
      vim.g.vimtex_compiler_latexmk_engines = { _ = "-xelatex" }
      vim.g.vimtex_view_method = "mupdf"
    end,
  },
  -- }}}
  -- web-devicons {{{
  {
    name = "web-devicons",
    "https://github.com/kyazdani42/nvim-web-devicons",
    config = function()
      require("nvim-web-devicons").set_icon {
        nimble = { icon = " ", color = "#f3d400", name = "nim" },
        nimja = { icon = "󰝴", color = "#444444", name = "ninja" },
        xd = { icon = "ξ", color = "#dd00cc", name = "xidoc" },
      }
    end,
  },
  -- }}}
  { name = "xidoc", "https://git.sr.ht/~xigoi/nvim-xidoc", ft = "xidoc" },
  -- woof {{{
  {
    name = "woof",
    "https://git.sr.ht/~xigoi/nvim-woof",
    config = function()
      vim.cmd.colorscheme "woof"
    end,
  },
  -- }}}
  -- yanky {{{
  {
    name = "yanky",
    "https://github.com/gbprod/yanky.nvim",
    keys = {
      { mode = { "n", "x" }, "y", "<Plug>(YankyYank)", desc = "Yank text" },
      { mode = { "n", "x" }, "Y", "<Plug>(YankyYank)$", desc = "Yank text to end of line" },
      { mode = { "n", "x" }, "p", "<Plug>(YankyPutAfter)", desc = "Put yanked text after cursor" },
      {
        mode = { "n", "x" },
        "P",
        "<Plug>(YankyPutBefore)",
        desc = "Put yanked text before cursor",
      },
      {
        mode = { "n", "x" },
        "gp",
        "<Plug>(YankyGPutAfter)",
        desc = "Put yanked text after selection",
      },
      {
        mode = { "n", "x" },
        "gP",
        "<Plug>(YankyGPutBefore)",
        desc = "Put yanked text before selection",
      },
      {
        mode = "n",
        "<c-p>",
        "<Plug>(YankyPreviousEntry)",
        desc = "Select previous entry through yank history",
      },
      {
        mode = "n",
        "<c-n>",
        "<Plug>(YankyNextEntry)",
        desc = "Select next entry through yank history",
      },
      {
        mode = "n",
        "-p",
        "<Plug>(YankyPutIndentAfterLinewise)",
        desc = "Put indented after cursor (linewise)",
      },
      {
        mode = "n",
        "-P",
        "<Plug>(YankyPutIndentBeforeLinewise)",
        desc = "Put indented before cursor (linewise)",
      },
      { mode = "n", ">p", "<Plug>(YankyPutIndentAfterShiftRight)", desc = "Put and indent right" },
      { mode = "n", "<p", "<Plug>(YankyPutIndentAfterShiftLeft)", desc = "Put and indent left" },
      { mode = "n", ">P", "<Plug>(YankyPutIndentBeforeShiftRight)", desc = "Put before and indent right" },
      { mode = "n", "<P", "<Plug>(YankyPutIndentBeforeShiftLeft)", desc = "Put before and indent left" },
      { mode = "n", "=p", "<Plug>(YankyPutAfterFilter)", desc = "Put after applying a filter" },
      { mode = "n", "=P", "<Plug>(YankyPutBeforeFilter)", desc = "Put before applying a filter" },
    },
    opts = {
      system_clipboard = { sync_with_ring = false },
      highlight = { timer = 100 },
      preserve_cursor_position = { enabled = true },
    },
  },
  -- }}}
}, {
  dev = { path = "~/nvim-plugins", patterns = { "https://git.sr.ht/~xigoi/" } },
  install = { colorscheme = { "koehler" } },
})

-- }}}
